#pragma once
#include <brpc/channel.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include "logger.hpp"

namespace bite_im{

// 1.封装单个服务的信道管理类：负责管理同一个服务的多个节点信道
class ServiceChannel {
public:
    using ptr = std::shared_ptr<ServiceChannel>;
    using ChannelPtr = std::shared_ptr<brpc::Channel>;

    ServiceChannel(const std::string &name):
        _service_name(name), _index(0){}

    //服务上线了一个节点，则调用append新增信道
    void append(const std::string &host) {
        //创捷新的brpc信道智能指针
        auto channel = std::make_shared<brpc::Channel>();
        brpc::ChannelOptions options;   //信道配置选项
        options.connect_timeout_ms = -1;//连接超时：-1表示不超时
        options.timeout_ms = -1;        //调用超时：-1表示不超时
        options.max_retry = 3;          //最大重试次数：3次
        options.protocol = "baidu_std"; //使用百度标准协议
    
        //初始化信道（连接到指定主机）
        int ret = channel->Init(host.c_str(), &options);
        if (ret == -1) {
            LOG_ERROR("初始化{}-{}信道失败!", _service_name, host);
            return;
        }

        //加锁保证线程安全，将新信道添加到管理容器中
        std::unique_lock<std::mutex> lock(_mutex);
        _hosts.insert(std::make_pair(host, channel));
        _channels.push_back(channel);
    }

    //服务下线了一个节点，将信道添加到管理容器中
    void remove(const std::string &host) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _hosts.find(host);
        if (it == _hosts.end()) {
            LOG_WARN("{}-{}节点删除信道时，没有找到信道信息！", _service_name, host);
            return;
        }

        //从信道列表中移除对应的信道 
        for (auto vit = _channels.begin(); vit != _channels.end(); ++vit) {
            if (*vit == it->second) {
                _channels.erase(vit);
                break;
            }
        }
        _hosts.erase(it);
    }

    //通过RR（Round-Robin，轮询）策略，获取一个channel用于发起对应服务的Rpc调用
    ChannelPtr choose() {
        std::unique_lock<std::mutex> lock(_mutex);
        if (_channels.size() == 0) {
            LOG_ERROR("当前没有能够提供 {} 服务的节点！", _service_name);
            return ChannelPtr();
        }
        //轮询选择，通过索引自增取模实现轮询
        int32_t idx = _index++ % _channels.size();
        return _channels[idx];
    }
    
private:
    std::mutex _mutex;
    int32_t _index;                   //当前轮转下标计数器，用于RR策略
    std::string _service_name;        //服务名称
    std::vector<ChannelPtr> _channels;//存储当前服务对应的信道的集合
    //主机地址与信息映射关系（用于快速查找和删除下线节点的信道）
    std::unordered_map<std::string, ChannelPtr> _hosts;
};

// 2. 总体的服务信道管理类：管理多个服务的信道，是上层对外的主要接口
class ServiceManager {
public:
    using ptr = std::shared_ptr<ServiceManager>;

    ServiceManager(){}

    //获取指定服务的节点信道（通过轮询策略）
    ServiceChannel::ChannelPtr choose(const std::string &service_name) {
        std::unique_lock<std::mutex> lock(_mutex);
        auto sit = _services.find(service_name);
        if (sit == _services.end()) {
            LOG_ERROR("当前没有能够提供 {} 服务的节点！", service_name);
            return ServiceChannel::ChannelPtr();
        }

        //调用对应服务的信道管理类的choose方法（轮询选择）
        return sit->second->choose();
    }

    //声明需要关注的服务：只有声明关注的服务，才会进行上下线管理
    void declared(const std::string &service_name) {
        std::unique_lock<std::mutex> lock(_mutex);
        _follow_service.insert(service_name);
    }

    //服务上线时调用的回调接口：将服务节点添加到管理中
    void onServiceOnline(const std::string &service_instance, const std::string &host) {
        //从服务实例名称中解析出服务名称
        std::string service_name = getServiceName(service_instance);
        ServiceChannel::ptr service;

        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 检查是否关注该服务，未关注则不处理
            auto fit = _follow_service.find(service_name);
            if (fit == _follow_service.end()) {
                LOG_DEBUG("{}-{} 服务上线了，但是当前并不关心！", service_name, host);
                return;
            }

            //查找该服务的信道管理实例，不存在则创建
            auto sit = _services.find(service_name);
            if (sit == _services.end()) {
                service = std::make_shared<ServiceChannel>(service_name);
                _services.insert(std::make_pair(service_name, service));
            } else {
                service = sit->second;
            }
        }

        if (!service) {
            LOG_ERROR("新增 {} 服务管理节点失败！", service_name);
            return;
        }

        //调用ServiceChannel的append方法添加新节点
        service->append(host);
        LOG_DEBUG("{}-{} 服务上线新节点，进行添加管理！", service_name, host);

    }

    //服务下线时调用的回调接口：从服务中删除指定的节点
    void onServiceOffline(const std::string &service_instance, const std::string &host) {
        std::string service_name = getServiceName(service_instance);
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            //检查是否关注改服务，为关注则不处理
            auto fit = _follow_service.find(service_name);
            if (fit == _follow_service.end()) {
                LOG_DEBUG("{}-{} 服务下线了，但是当前并不关心！", service_name, host);
                return;
            }

            //查找该服务的信道管理实例，不存在则创建
            auto sit = _services.find(service_name);
            if (sit == _services.end()) {
                LOG_WARN("删除{}服务节点时，没有找到管理对象", service_name);
                return;
            }

            service = sit->second;
        }

        //调用ServiceChannel的remove方法删除节点
        service->remove(host);
        LOG_DEBUG("{}-{} 服务下线节点，进行删除管理！", service_name, host);
    }

private:
    //从服务实例中提取服务的名称（格式：服务名/实例名）
    std::string getServiceName(const std::string &service_instance) {
        auto pos = service_instance.find_last_of('/');
        if (pos == std::string::npos) return service_instance;
        return service_instance.substr(0, pos); // 截取斜杠前的部分作为服务名
    }

private:
    std::mutex _mutex;
    //存储关注服务的集合：只有在集合中的服务才能被管理
    std::unordered_set<std::string> _follow_service;
    //服务名称到其信道管理实例的映射：管理多个服务的信道
    std::unordered_map<std::string, ServiceChannel::ptr> _services;
};
}